package server;

import common.LogUtil;
import common.Message;
import common.NetworkUtil;
import common.Protocol;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * 处理客户端通信
 */
public class ClientHandler {
    private static final Logger logger = LogUtil.getLogger(ClientHandler.class.getName());

    // 关联的代理服务器
    private final ProxyServer server;

    // 客户端通道
    private final SocketChannel clientChannel;

    // 客户端ID
    private String clientId;

    // 认证状态
    private boolean authenticated = false;

    // 最后活动时间
    private long lastActivityTime;

    /**
     * 构造函数
     */
    public ClientHandler(ProxyServer server, SocketChannel clientChannel) {
        this.server = server;
        this.clientChannel = clientChannel;
        this.lastActivityTime = System.currentTimeMillis();
        this.clientId = clientChannel.socket().getRemoteSocketAddress().toString();
    }

    /**
     * 开始处理客户端消息
     */
    public void start() {
        // 注册到客户端管理器
        server.getClientManager().addClient(clientId, this);

        logger.info("Client connected: " + clientId);

        // 在单独的线程中处理客户端消息
        server.getExecutor().execute(this::messageLoop);
    }

    /**
     * 消息处理循环
     */
    private void messageLoop() {
        try {
            while (clientChannel.isOpen()) {
                // 读取消息
                Message message = NetworkUtil.readMessage(clientChannel);

                // 更新活动时间
                updateLastActivityTime();

                // 处理消息
                handleMessage(message);
            }
        } catch (IOException e) {
            logger.log(Level.INFO, "Client disconnected: " + clientId, e);
        } catch (Exception e) {
            logger.log(Level.SEVERE, "Error handling client message: " + clientId, e);
        } finally {
            close();
        }
    }

    /**
     * 处理消息
     */
    private void handleMessage(Message message) throws IOException {
        switch (message.getType()) {
            case Protocol.MSG_TYPE_AUTH:
                handleAuth(message);
                break;
            case Protocol.MSG_TYPE_HEARTBEAT:
                handleHeartbeat(message);
                break;
            case Protocol.MSG_TYPE_NEW_CONN:
                handleNewConnection(message);
                break;
            case Protocol.MSG_TYPE_DATA:
                handleData(message);
                break;
            case Protocol.MSG_TYPE_CLOSE_CONN:
                handleCloseConnection(message);
                break;
            default:
                logger.warning("Unknown message type: " + message.getType());
        }
    }

    /**
     * 处理认证消息
     */
    private void handleAuth(Message message) throws IOException {
        String token = new String(message.getData(), StandardCharsets.UTF_8);

        // 检查认证令牌
        boolean success = checkAuth(token);

        // 构造认证响应
        byte[] responseData = new byte[1];
        responseData[0] = (byte) (success ? 1 : 0);
        Message response = new Message(Protocol.MSG_TYPE_AUTH_RESP,
                message.getRequestId(), responseData);

        // 发送响应
        NetworkUtil.writeMessage(clientChannel, response);

        // 设置认证状态
        authenticated = success;

        logger.info("Client " + clientId + " authentication " +
                (success ? "succeeded" : "failed"));
    }

    /**
     * 检查认证令牌
     */
    private boolean checkAuth(String token) {
        if (!server.getConfig().isAuthEnabled()) {
            return true;
        }

        return token.equals(server.getConfig().getAuthToken());
    }

    /**
     * 处理心跳消息
     */
    private void handleHeartbeat(Message message) throws IOException {
        // 响应心跳
        NetworkUtil.writeMessage(clientChannel, Message.heartbeat());
    }

    /**
     * 处理新连接请求
     */
    private void handleNewConnection(Message message) {
        if (!authenticated) {
            logger.warning("Unauthenticated client tried to establish connection: " + clientId);
            return;
        }

        ByteBuffer buffer = ByteBuffer.wrap(message.getData());
        int connectionId = buffer.getInt();

        logger.info("Handling new connection request: " + connectionId);

        // 通知客户端连接已接受
        try {
            ByteBuffer responseData = ByteBuffer.allocate(4);
            responseData.putInt(connectionId);
            Message response = new Message(Protocol.MSG_TYPE_NEW_CONN, message.getRequestId(), responseData.array());
            sendMessage(response);
        } catch (IOException e) {
            logger.log(Level.SEVERE, "Failed to accept new connection", e);
        }
    }

    /**
     * 处理数据消息
     */
    private void handleData(Message message) {
        if (!authenticated) {
            logger.warning("Unauthenticated client tried to send data: " + clientId);
            return;
        }

        ByteBuffer buffer = ByteBuffer.wrap(message.getData());
        int connectionId = buffer.getInt();

        // 提取数据部分
        byte[] data = new byte[buffer.remaining()];
        buffer.get(data);

        // 获取用户连接
        UserConnection connection = server.getProxyManager().getUserConnection(connectionId);
        if (connection != null) {
            try {
                connection.writeToUser(data);
            } catch (IOException e) {
                logger.log(Level.WARNING, "Error forwarding data to user: " + connectionId, e);
                try {
                    // 通知客户端连接已关闭
                    Message closeMsg = Message.closeConnection(connectionId);
                    sendMessage(closeMsg);
                } catch (IOException ex) {
                    logger.log(Level.WARNING, "Error sending close notification", ex);
                }
                connection.close();
            }
        } else {
            logger.warning("Connection not found for data: " + connectionId);
        }
    }

    /**
     * 处理关闭连接消息
     */
    private void handleCloseConnection(Message message) {
        if (!authenticated) {
            logger.warning("Unauthenticated client tried to close connection: " + clientId);
            return;
        }

        // TODO: 处理关闭连接请求
    }

    /**
     * 发送消息
     */
    public void sendMessage(Message message) throws IOException {
        NetworkUtil.writeMessage(clientChannel, message);
    }

    /**
     * 更新最后活动时间
     */
    public void updateLastActivityTime() {
        this.lastActivityTime = System.currentTimeMillis();
    }

    /**
     * 获取最后活动时间
     */
    public long getLastActivityTime() {
        return lastActivityTime;
    }

    /**
     * 检查客户端是否超时
     */
    public boolean isTimeout() {
        return System.currentTimeMillis() - lastActivityTime > Protocol.CONNECTION_TIMEOUT;
    }

    /**
     * 关闭客户端连接
     */
    public void close() {
        try {
            // 从管理器中移除
            server.getClientManager().removeClient(clientId);

            // 关闭通道
            if (clientChannel.isOpen()) {
                clientChannel.close();
            }

            logger.info("Client disconnected: " + clientId);
        } catch (IOException e) {
            logger.log(Level.WARNING, "Error closing client channel: " + clientId, e);
        }
    }

    /**
     * 获取客户端ID
     */
    public String getClientId() {
        return clientId;
    }

    /**
     * 获取客户端通道
     */
    public SocketChannel getClientChannel() {
        return clientChannel;
    }

    /**
     * 检查认证状态
     */
    public boolean isAuthenticated() {
        return authenticated;
    }
}
